#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <cassert>

#include "util.h"
#include "sent.h"
#include "structure.h"
#include "classifier.h"

using namespace std;

map <string, int> s2n; // mapping from strings to numbers
vector <string> n2s; // reverse mapping

// all strings of words
pn sw; // entity and relation examples

map <string, int> dict,gaz;

int EXTRACTOR = -1;

double THRESH=0.01; // threshold for the confidence under a subtree
int BEAM=5; // 5 beam width for the parser
int RWINDOW=5; // how many surrounding words to consider
int EWINDOW=2; // how many surrounding words to consider

int CL;

// Features
bool _CAP=true, _DICT=false, _GAZ=true, _POS=true, _G=true, _MENT=true, _ING=true;

vector <bool> fdi, fga, fcap, fment,fing;
vector <string> fg;

bool inverse(const string &s1, const string &s2) {
   if (s1.size() + 2 == s2.size()) {
      if (s2[s2.size()-1] != '1') return false;
      if (s2[s2.size()-2] != '-') return false;
      for (int i=0; i<s1.size(); ++i) if (s1[i] != s2[i]) return false;
      return true;
   }
   if (s2.size() + 2 == s1.size()) {
      if (s1[s1.size()-1] != '1') return false;
      if (s1[s1.size()-2] != '-') return false;
      for (int i=0; i<s2.size(); ++i) if (s2[i] != s1[i]) return false;
      return true;
   }
   return false;
}

bool inverseProd(const vector <string> &s1, const vector <string> &s2) {
   if (s1.size() != s2.size()) return false;
   if (! inverse(s1[0],s2[0])) return false;
   return true;
}

void readDictGaz() {
   ifstream in("dictionary");
   assert(in);
   while (in) {
      string s;
      in>>s;
      if (in) {
        dict[s]=1;
      }
   }
   in.close();

   in.open("gazetteer");
   assert(in);
   while (in) {
      string s;
      in>>s;
      if (in) {
         gaz[s] = 1;
      }
   }
   in.close();
}

void collectPosNeg(vector <classifier> &cl, const vector <structure> &tr, const vector <sent> &str) {
   assert(tr.size()==str.size());
   if (EXTRACTOR==JOINT || EXTRACTOR==RELATION_ONLY) {
      for (int i=0; i<tr.size(); ++i) {
         vector <vector <int> > s,e;
         vector <vector <string> > prs;

	 vector <vector <vector <string> > > path;
	 vector <vector <vector <double> > > pathProb;
         tr[i].giveInternalEgs(prs,s,e,path,pathProb);
	 vector <int> rl;
	 vector <int> sl,el;
	 tr[i].giveLeafLabels(sl,el,rl,tr[i].rlevel(),0,0);
	 vector <int> words=str[i].giveWords(), postags=str[i].givePostags();
	 for (int p=0; p<prs.size(); ++p) {
	    vector <int> w,pt,bw,aw,bp,ap,ntw,ntp;
	    int st = s[p][0];
	    int en = e[p][(int)e[p].size()-1];
	    for (int j=st; j<=en; ++j) {
	       int a;
	       for (a=0; a<sl.size(); ++a) {
		  if (j==sl[a]) {
		     if ((sl[a]==s[p][0] && el[a]==e[p][0])||
			   (sl[a]==s[p][(int)e[p].size()-1] && el[a]==e[p][(int)e[p].size()-1])) {
		     }
		     else break;
		  }
	       }
	       if (a < sl.size()) {
		  w.push_back(rl[a]);
		  pt.push_back(rl[a]);
		  j=el[a];
	       }
	       else {
	          w.push_back(words[j]);
	          pt.push_back(postags[j]);
	       }
	    }
	    int b=st-RWINDOW;
	    if (b < 0) b=0;
	    for (int j=b; j<st; ++j) {
	       bw.push_back(words[j]);
	       bp.push_back(postags[j]);
	    }
	    int a=en+RWINDOW;
	    if (a > (int)words.size()-1) a = (int)words.size()-1; 
	    for (int j=en+1; j<=a; ++j) {
	       aw.push_back(words[j]);
	       ap.push_back(postags[j]);
	    }
	    st = e[p][0]+1;
	    en = s[p][(int)s[p].size()-1]-1;
	    //ntw.push_back(mapInsert(prs[p][1]));
	    //ntp.push_back(mapInsert(prs[p][1]));
	    for (int j=st; j<=en; ++j) {
	       int a;
	       for (a=0; a<sl.size(); ++a) {
		  if (j==sl[a]) {
		     break;
		  }
	       }
	       if (a < sl.size()) {
		  ntw.push_back(rl[a]);
		  ntp.push_back(rl[a]);
		  j = el[a];
	       }
	       else {
	          ntw.push_back(words[j]);
	          ntp.push_back(postags[j]);
	       }
	    }
	    //ntw.push_back(mapInsert(prs[p][2]));
	    //ntp.push_back(mapInsert(prs[p][2]));
	    //
	    /*
	    for (int a=0; a<w.size(); ++a) {
	       cout<<n2s[w[a]]<<" ";
	    }
	    cout<<"\n";
	    for (int a=0; a<ntw.size(); ++a) {
	       cout<<n2s[ntw[a]]<<" ";
	    }
	    cout<<"\n\n";
	    */
	    posNeg eg(w,pt,bw,aw,bp,ap,ntw,ntp,false);

	    eg.addPath(path[p],pathProb[p]);

            for (int c=0; c<cl.size(); ++c) {
	       vector <string> pr = cl[c].giveProd();
	       if (pr[0][0]=='N' && pr[0][1]=='R') {
		  if (prs[p][0][0]=='N' && prs[p][0][1]=='R') {
		     cl[c].addPos(eg);
		  }
		  else {
		     cl[c].addNeg(eg);
		  }
	       }
	       else {
	       if (prs[p]==pr) {
		  // positive example
		  cl[c].addPos(eg);
	       }
	       else {
		  if (prs[p].size()==pr.size()) {
		     int f=0;
		     for (int e=1; e<prs[p].size(); ++e) {
		        if (prs[p][e] != pr[e]) {
			   ++f;
		        }
		     }
		     /*
		     bool b=true;
		     if (pr.size()==3) {
			if (pr[1] != pr[2]) {
			   if (inverseProd(prs[p],pr)) b=false;
			}
		     }*/
		     if (f == 0) {
		     // negative example
		        //writeVector(cout,prs[p]);
		        //writeVector(cout,pr);
			//cout<<"\n\n";
			cl[c].addNeg(eg);
		     }
		     else {
			//if (cl[c].posSize()*5 >= cl[c].negSize()) {
			//if (f==1) {
			  // cl[c].addNeg1(eg);
			//}
		     }
			
		  }

		  }
	       }
	    }
         }
      }
   }
   if (EXTRACTOR==JOINT || EXTRACTOR==ENTITY_ONLY) {
      for (int i=0; i<tr.size(); ++i) {
         vector <int> s,e;
         vector <vector <string> > prs;
         tr[i].giveBottomEgs(prs,s,e);
	 vector <int> words=str[i].giveWords(), postags=str[i].givePostags();
	 for (int p=0; p<prs.size(); ++p) {
	    vector <int> w,pt,bw,aw,bp,ap,ntw,ntp;
	    int st=s[p];
	    int en=e[p];
	    for (int j=st; j<=en; ++j) {
	       w.push_back(words[j]);
	       pt.push_back(postags[j]);
	    }
	    int b=st-EWINDOW;
	    if (b < 0) b=0;
	    for (int j=b; j<st; ++j) {
	       bw.push_back(words[j]);
	       bp.push_back(postags[j]);
	    }
	    int a=en+EWINDOW;
	    if (a > (int)words.size()-1) a = (int)words.size()-1; 
	    for (int j=en+1; j<=a; ++j) {
	       aw.push_back(words[j]);
	       ap.push_back(postags[j]);
	    }
	    //ntw=w;
	    //ntp=pt;
	    posNeg eg(w,pt,bw,aw,bp,ap,ntw,ntp,true);
	     
	    for (int c=0; c<cl.size(); ++c) {
	       vector <string> pr = cl[c].giveProd();
	       if (prs[p]==pr) {
		  // positive example
		  cl[c].addPos(eg);
	       }
	       else {
		  if (prs[p].size()==pr.size()) {
		     int f=0;
		     for (int e=1; e<prs[p].size(); ++e) {
		        if (prs[p][e] != pr[e]) {
			   ++f;
		        }
		     }
		     if (f == 0) {
		        // negative example
			cl[c].addNeg(eg);
		     }
		  }
	       }
	    }
	 }
      }
   }
   for (int i=0; i<cl.size(); ++i) {
      cl[i].sampleNegatives();
   }
}

/*
void collectPosNegAll(vector <classifier> &cl, const vector <structure> &all, const vector <sent> &sall, const vector <structure> &tr, const vector <sent> &str) {
   assert(all.size()==sall.size());
   if (EXTRACTOR==JOINT || EXTRACTOR==RELATION_ONLY) {
      for (int i=0; i<all.size(); ++i) {
         vector <vector <int> > s,e;
         vector <vector <string> > prs;
         all[i].giveInternalEgs(prs,s,e);
	 vector <int> rl;
	 vector <int> sl,el;
	 all[i].giveLeafLabels(sl,el,rl,all[i].rlevel(),0,0);
	 vector <int> words=sall[i].giveWords(), postags=sall[i].givePostags();
	 for (int p=0; p<prs.size(); ++p) {
	    vector <int> w,pt,bw,aw,bp,ap,ntw,ntp;
	    int st = s[p][0];
	    int en = e[p][(int)e[p].size()-1];
	    for (int j=st; j<=en; ++j) {
	       int a;
	       for (a=0; a<sl.size(); ++a) {
		  if (j==sl[a]) {
		     if ((sl[a]==s[p][0] && el[a]==e[p][0])||
			   (sl[a]==s[p][(int)e[p].size()-1] && el[a]==e[p][(int)e[p].size()-1])) {
		     }
		     else break;
		  }
	       }
	       if (a < sl.size()) {
		  w.push_back(rl[a]);
		  pt.push_back(rl[a]);
		  j=el[a];
	       }
	       else {
	          w.push_back(words[j]);
	          pt.push_back(postags[j]);
	       }
	    }
	    int b=st-RWINDOW;
	    if (b < 0) b=0;
	    for (int j=b; j<st; ++j) {
	       bw.push_back(words[j]);
	       bp.push_back(postags[j]);
	    }
	    int a=en+RWINDOW;
	    if (a > (int)words.size()-1) a = (int)words.size()-1; 
	    for (int j=en+1; j<=a; ++j) {
	       aw.push_back(words[j]);
	       ap.push_back(postags[j]);
	    }
	    st = e[p][0]+1;
	    en = s[p][(int)s[p].size()-1]-1;
	    //ntw.push_back(mapInsert(prs[p][1]));
	    //ntp.push_back(mapInsert(prs[p][1]));
	    for (int j=st; j<=en; ++j) {
	       int a;
	       for (a=0; a<sl.size(); ++a) {
		  if (j==sl[a]) {
		     break;
		  }
	       }
	       if (a < sl.size()) {
		  ntw.push_back(rl[a]);
		  ntp.push_back(rl[a]);
		  j = el[a];
	       }
	       else {
	          ntw.push_back(words[j]);
	          ntp.push_back(postags[j]);
	       }
	    }
	    //ntw.push_back(mapInsert(prs[p][2]));
	    //ntp.push_back(mapInsert(prs[p][2]));
	    //
	    posNeg eg(w,pt,bw,aw,bp,ap,ntw,ntp,false);

            for (int c=0; c<cl.size(); ++c) {
	       vector <string> pr = cl[c].giveProd();
	       if (pr[0][0]=='N' && pr[0][1]=='R') {
		  if (prs[p][0][0]=='N' && prs[p][0][1]=='R') {
		     cl[c].addPos(eg);
		  }
		  else {
		     cl[c].addNeg(eg);
		  }
	       }
	       else {
	       if (prs[p]==pr) {
		  // positive example
		  cl[c].addPos(eg);
	       }
	       else {
		  if (prs[p].size()==pr.size()) {
		     int f=0;
		     for (int e=1; e<prs[p].size(); ++e) {
		        if (prs[p][e] != pr[e]) {
			   ++f;
		        }
		     }
		     if (f == 0) {
		     // negative example
		        //writeVector(cout,prs[p]);
		        //writeVector(cout,pr);
			//cout<<"\n\n";
			cl[c].addNeg(eg);
		     }
		     else {
			//if (cl[c].posSize()*5 >= cl[c].negSize()) {
			//if (f==1) {
			  // cl[c].addNeg1(eg);
			//}
		     }
			
		  }

		  }
	       }
	    }
         }
      }
   }
   if (EXTRACTOR==JOINT || EXTRACTOR==ENTITY_ONLY) {
      for (int i=0; i<tr.size(); ++i) {
         vector <int> s,e;
         vector <vector <string> > prs;
         tr[i].giveBottomEgs(prs,s,e);
	 vector <int> words=str[i].giveWords(), postags=str[i].givePostags();
	 for (int p=0; p<prs.size(); ++p) {
	    vector <int> w,pt,bw,aw,bp,ap,ntw,ntp;
	    int st=s[p];
	    int en=e[p];
	    for (int j=st; j<=en; ++j) {
	       w.push_back(words[j]);
	       pt.push_back(postags[j]);
	    }
	    int b=st-EWINDOW;
	    if (b < 0) b=0;
	    for (int j=b; j<st; ++j) {
	       bw.push_back(words[j]);
	       bp.push_back(postags[j]);
	    }
	    int a=en+EWINDOW;
	    if (a > (int)words.size()-1) a = (int)words.size()-1; 
	    for (int j=en+1; j<=a; ++j) {
	       aw.push_back(words[j]);
	       ap.push_back(postags[j]);
	    }
	    //ntw=w;
	    //ntp=pt;
	    posNeg eg(w,pt,bw,aw,bp,ap,ntw,ntp,true);
	     
	    for (int c=0; c<cl.size(); ++c) {
	       vector <string> pr = cl[c].giveProd();
	       if (prs[p]==pr) {
		  // positive example
		  cl[c].addPos(eg);
	       }
	       else {
		  if (prs[p].size()==pr.size()) {
		     int f=0;
		     for (int e=1; e<prs[p].size(); ++e) {
		        if (prs[p][e] != pr[e]) {
			   ++f;
		        }
		     }
		     if (f == 0) {
		        // negative example
			cl[c].addNeg(eg);
		     }
		  }
	       }
	    }
	 }
      }
   }
   for (int i=0; i<cl.size(); ++i) {
      cl[i].sampleNegatives();
   }
}*/



void writeUsage() {
   //cout<<"USAGE: ./main {-joint|-pipeline|-relation-only|-entity-only} -fold FOLD [-train TRAINSIZE]\n";
}

int main(int argc, char **argv) {
   int fold;
   int TRSIZE=1000000;
   bool testOnTrain=false;
   //bool testOnTrain=true;
   bool onlyAdjacent=true;

   if (argc < 3) {
      writeUsage();
      exit(1);
   }

   int i=0;
   bool bfold=false;
   int seed=1;
   while (i < argc) {
      string a = argv[i];
      if (a=="-train") {
         ++i; 
         TRSIZE = atoi(argv[i]);
      }
      if (a=="-joint") {
	 EXTRACTOR = JOINT;
      }
      if (a=="-pipeline") {
	 EXTRACTOR = JOINT;
	 BEAM = 1;
      }
      if (a=="-relation-only") {
	 EXTRACTOR = RELATION_ONLY;
	 BEAM = 1;
      }
      if (a=="-entity-only") {
	 EXTRACTOR = ENTITY_ONLY;
	 BEAM = 1;
      }
      if (a=="-fold") {
         ++i; 
         fold = atoi(argv[i]);
	 bfold=true;
      }
      if (a=="-seed") {
         ++i; 
         seed = atoi(argv[i]);
      }
      ++i;
   }
   if (!bfold || EXTRACTOR==-1) {
      writeUsage();
      exit(1);
   }

   // read dictionary and gazetteer
   readDictGaz();

   ifstream in("conll04.xml");
   assert(in);
   vector <sent> s;
   bool r=true;
   int ind=0;
   //int cid=0;
   while (r) {
      sent tmp;
      r = tmp.read(in,onlyAdjacent);
      if (r) {
	 if (tmp.relSize() > 0) {
	 //if (tmp.entSize()==3 && tmp.relSize() > 0) 
	    s.push_back(tmp);
	    //cout<<"id="<<cid<<"\n";
	    //cout<<tmp<<"\n\n";
	 }
	 //++cid;
      }
      ++ind;
      //if (ind==2000) break;
   }
   in.close();
   /*
   vector <int> rc(100,0);
   vector <int> ec(100,0);
   for (int i=0; i<s.size(); ++i) {
      ++rc[s[i].relSize()];
      ++ec[s[i].entSize()];
   }
   for (int i=0; i<ec.size(); ++i) {
      if (ec[i] != 0) {
	 cout<<i<<" entities in "<<ec[i]<<" sentences\n";
      }
   }
   for (int i=0; i<rc.size(); ++i) {
      if (rc[i] != 0) {
	 cout<<i<<" relations in "<<rc[i]<<" sentences\n";
      }
   }
   exit(1);*/

   srand(seed);
   random_shuffle(s.begin(), s.end());

   vector <structure> all;
   for (int i=0; i<s.size(); ++i) {
      //cout<<s[i]<<"\n";
      all.push_back(s[i].giveStructure());
      //cout<<all[all.size()-1]<<"\n";
      //cout<<"Out\n";
      //if (i==TRSIZE) break;
   }
   //exit(1);
   
   in.open("conll04.xml");
   assert(in);
   vector <sent> comp_s;
   r=true;
   while (r) {
      sent tmp;
      r = tmp.read(in,false);
      if (r) comp_s.push_back(tmp);
   }
   in.close();
   
   vector <structure> at, tr, te;
   vector <sent> sat, str, ste;
   for (int i=0; i<all.size(); ++i) {
      if (i % 5 == fold) {
         if (i < TRSIZE) {
	 if (!testOnTrain) {
            te.push_back(all[i]);
            ste.push_back(s[i]);
            at.push_back(all[i]);
            sat.push_back(s[i]);
	 }
	 }
      }
      else {
         if (i < TRSIZE) {
            tr.push_back(all[i]);
            str.push_back(s[i]);
            at.push_back(all[i]);
            sat.push_back(s[i]);
	    if (testOnTrain) {
               te.push_back(all[i]);
               ste.push_back(s[i]);
	    }
	 }
      }
   }

   vector <vector <string> > prods;
   vector <int> freq;
   for (int i=0; i<tr.size(); ++i) {
      vector <vector <string> > pr;
      tr[i].giveProds(pr);
      for (int j=0; j<pr.size(); ++j) {
         bool f=false;
         for (int p=0; p<prods.size(); ++p) {
            if (pr[j]==prods[p]) {
               ++freq[p];
               f=true;
               break;
            }
         }
         if (!f) {
            prods.push_back(pr[j]);
            freq.push_back(1);
         }
      }
   }

   /*
   for (int i=0; i<prods.size(); ++i) {
      cout<<freq[i]<<" ";
      cout<<prods[i][0]<<" -> ";
      for (int j=1; j<prods[i].size(); ++j) {
	 cout<<prods[i][j]<<" ";
      }
      cout<<"\n";
   }
   exit(1);
   */

   // form classifiers for each production
   vector <classifier> cl;
   for (int i=0; i<prods.size(); ++i) {
      if (prods[i].size()==2) {
	 cl.push_back(classifier(prods[i],true));
      }
      else {
	 cl.push_back(classifier(prods[i],false));
      }
   }

   // collect positive and negative examples for each classifier
   //collectPosNegAll(cl,te,ste,tr,str); //?
   collectPosNeg(cl,tr,str);

   /*
   for (int i=0; i<cl.size(); ++i) {
      string s=cl[i].giveLhs();
      if (s.size() > 1 && s[0]=='N' && s[1]=='R') {
	 cl[i].setNrd();
	 CL=i; // ?
	 break; // ?
      }
   }*/

   // train the classifiers
   for (int i=0; i<cl.size(); ++i) {
      if (cl[i].posSize() + cl[i].negSize() >= 1) { 
	    //cout<<"==============================\n"<<cl[i];
	    //cout<<"==============================\n";
	    cl[i].writeProd(cout);
	    cout<<"#POS: "<<cl[i].posSize()<<" #NEG: "<<cl[i].negSize()<<"\n";
	    cl[i].train();
	    //if (!cl[i].ifNr()) cout<<"Accuracy: "<<cl[i].accuracy()<<" %\n\n\n";
      }
   }
   //exit(1);
   // testing
   vector <structure> ans;
   for (int i=0; i<ste.size(); ++i) {
      vector <int> words,postags;
      words = ste[i].giveWords();
      postags = ste[i].givePostags();

      vector <int> st,en;
      vector <string> et;
      if (EXTRACTOR==RELATION_ONLY) {
         ste[i].giveEntities(et,st,en);
         structure p(et,st,en);
         //cout<<ste[i]<<"\n";
         p.parse(cl,words,postags);
         //cout<<p<<"\n\n\n";
         ans.push_back(p);
      }
      else {
         ste[i].giveCandidateEntities(st,en);
         structure p(st,en);
         //cout<<ste[i]<<"\n";
         p.parse(cl,words,postags);
         //cout<<p<<"\n\n\n";
         ans.push_back(p);
      }
   }

   // evaluation
   vector <string> label;
   vector <int> c,o,mc,mo;
   for (int i=0; i<te.size(); ++i) {
      vector <string> cp,op;
      vector <int> cs,ce,os,oe;
      //cout<<ste[i]<<"\n";
      //cout<<te[i]<<"\n";
      te[i].giveFirstRelEntLabels(cp,cs,ce);
      for (int a=0; a<cp.size(); ++a) {
	 //cout<<"In: "<<cp[a]<<" "<<cs[a]<<" "<<ce[a]<<"\n";
      }
      ans[i].giveFirstRelEntLabels(op,os,oe);
      for (int a=0; a<op.size(); ++a) {
	 //cout<<"Out: "<<op[a]<<" "<<os[a]<<" "<<oe[a]<<"\n";
      }

      for (int j=0; j<cp.size(); ++j) {
         int k;
         for (k=0; k<label.size(); ++k) {
	    if (label[k]==cp[j]) break;
         }
	 if (k==label.size()) {
	    label.push_back(cp[j]);
	    c.push_back(0);
	    o.push_back(0);
	    mc.push_back(0);
	    mo.push_back(0);
	 }
	 ++c[k];
	 if (ans[i].entityMatch(cs[j],ce[j],cp[j])) ++mc[k];
      }
      for (int j=0; j<op.size(); ++j) {
         int k;
         for (k=0; k<label.size(); ++k) {
	    if (label[k]==op[j]) break;
         }
	 if (k==label.size()) {
	    label.push_back(op[j]);
	    c.push_back(0);
	    o.push_back(0);
	    mc.push_back(0);
	    mo.push_back(0);
	 }
	 ++o[k];
	 if (te[i].entityMatch(os[j],oe[j],op[j])) ++mo[k];
      }
   }
   for (int i=0; i<label.size(); ++i) {
      //cout<<label[i]<<"-rel ";
      printf("%s-rel ",label[i].c_str());
      //cout<<"Total="<<c[i]<<" Found="<<o[i]<<" Matched="<<mc[i]<<"\n";
      printf("Total=%d Found=%d MatchedR=%d MatchedP=%d\n",c[i],o[i],mc[i],mo[i]);
      double r,p;
      if (c[i] > 0) {
	 r = 100*mc[i]/c[i];
	 //cout<<"Recall: "<<r<<" %\n";
	 printf("Recall: %f\n",r);
      }
      if (o[i] > 0) {
	 p = 100*mo[i]/o[i];
	 //cout<<"Precision: "<<p<<" %\n";
	 printf("Precision: %f\n",p);
      }
      if (c[i] > 0 && o[i] > 0) {
	 if (p+r>0) {
	    //cout<<"F-measure: "<<2*p*r/(p+r)<<" %\n";
	    printf("F-measure: %f\n",2*p*r/(p+r));
	 }
      }
      //cout<<"\n\n";
      printf("\n\n");
   }

   label.clear();
   c.clear();
   o.clear();
   mc.clear();
   mo.clear();
   for (int i=0; i<te.size(); ++i) {
      //cout<<ste[i]<<"\n";
      //cout<<ans[i]<<"\n\n";
      vector <string> cp,op;
      vector <int> cs1,ce1,cs2,ce2,os1,oe1,os2,oe2;

      te[i].giveFirstLabels(cp,cs1,ce1,cs2,ce2);
      //for (int a=0; a<cp.size(); ++a) {
	// cout<<"In: "<<cp[a]<<" "<<cs1[a]<<" "<<ce1[a]<<" "<<cs2[a]<<" "<<ce2[a]<<"\n";
      //}
      ans[i].giveFirstLabels(op,os1,oe1,os2,oe2);
      //for (int a=0; a<cp.size(); ++a) {
	// cout<<"Out: "<<op[a]<<" "<<os1[a]<<" "<<oe1[a]<<" "<<os2[a]<<" "<<oe2[a]<<"\n";
      //}

//      cout<<"---------------------------\n";
      for (int j=0; j<cp.size(); ++j) {
         int k;
         for (k=0; k<label.size(); ++k) {
	    if (label[k]==cp[j]) break;
         }
	 if (k==label.size()) {
	    label.push_back(cp[j]);
	    c.push_back(0);
	    o.push_back(0);
	    mc.push_back(0);
	    mo.push_back(0);
	 }
	 ++c[k];
	 for (int e=0; e<op.size(); ++e) {
	    if (op[e]==cp[j] && os1[e]==cs1[j] && oe1[e]==ce1[j] && os2[e]==cs2[j] && oe2[e]==ce2[j]) {
	       ++mc[k];
	    }
	 }
      }
      for (int j=0; j<op.size(); ++j) {
	 //cout<<"\n"<<op[j]<<" ("<<os1[j]<<" "<<oe1[j]<<") "<<" ("<<os2[j]<<" "<<oe2[j]<<")\n";
         int k;
         for (k=0; k<label.size(); ++k) {
	    if (label[k]==op[j]) break;
         }
	 if (k==label.size()) {
	    label.push_back(op[j]);
	    c.push_back(0);
	    o.push_back(0);
	    mc.push_back(0);
	    mo.push_back(0);
	 }
	 ++o[k];
	 for (int e=0; e<cp.size(); ++e) {
	    if (op[j]==cp[e] && os1[j]==cs1[e] && oe1[j]==ce1[e] && os2[j]==cs2[e] && oe2[j]==ce2[e]) {
	       ++mo[k];
	       //cout<<"Matched\n";
	    }
	 }
      }
   }
   for (int i=0; i<label.size(); ++i) {
      //cout<<label[i]<<" ";
      printf("%s ",label[i].c_str());
      //cout<<"Total="<<c[i]<<" Found="<<o[i]<<" Matched="<<mc[i]<<"\n";
      printf("Total=%d Found=%d MatchedR=%d MatchedP=%d\n",c[i],o[i],mc[i],mo[i]);
      double r,p;
      if (c[i] > 0) {
	 r = 100*mc[i]/c[i];
	 //cout<<"Recall: "<<r<<" %\n";
	 printf("Recall: %f\n",r);
      }
      if (o[i] > 0) {
	 p = 100*mo[i]/o[i];
	 //cout<<"Precision: "<<p<<" %\n";
	 printf("Precision: %f\n", p);
      }
      if (c[i] > 0 && o[i] > 0) {
	 if (p+r>0) {
	    //cout<<"F-measure: "<<2*p*r/(p+r)<<" %\n";
	    printf("F-measure: %f\n", 2*p*r/(p+r));
	 }
      }
      //cout<<"\n\n";
      printf("\n");
   }
}
